/* ！！！Promise求阶乘！！！ */
function fn1() {
  /* 乘法函数 将结果由回调函数给出 */
  const multiply = (a, b, callback) => {
    setTimeout(() => callback(a * b), 2000);
  };
  // multiply(2,3,(ret)=>console.log("ret=",ret))

  /* 链式回调 */
  const mulPromise = (a, b) => {
    return new Promise(
      /* executor */
      (resolve, reject) => {
        // multiply(2,3,(ret)=>console.log("ret=",ret))//回调函数中得到结果打印之
        multiply(a, b, (ret) => resolve(ret)); //回调函数中得到结果履约之
      }
    );
  };

  mulPromise(2, 3) //开局一只【求二三之积的Promise】 将来履约6
    .then((ret) => 6 * 4) //前述履约履约6  继续向后履约24（臣妾很能 立即履约24）
    .then((ret) => mulPromise(ret, 5)) //前述履约履约24 继续返回一只【求24*5的Promise】 （臣妾没法立刻返回120） 将来履约120
    .then((ret) => console.log("ret=", ret)); //前述履约履约120 直接打印

  ~(async function awaitDemo() {
    try {
      // 死等await右侧的Promise履约
      let ret = await mulPromise(2, 3);

      // 死等await右侧的Promise履约
      ret = await mulPromise(ret, 4);

      // 死等await右侧的Promise履约
      ret = await mulPromise(ret, 5);
      console.log(ret);
    } catch (err) {
      // 如果try以内有Promise毁约 捕获其毁约的原因
      console.log("err=", err);
    }
  })();
}
// fn1();

/* 函数的Promise化 */
function fn2() {
  // 同步函数
  function add(a, b) {
    return a + b;
  }

  // 带有异步回调的函数
  function multiply(a, b, callback) {
    setTimeout(() => callback(a * b), 1000);
  }
  // multiply(2, 3, (ret) => console.log("ret=", ret));

  /* 异步函数的Promise化 */
  function promisify(fn) {
    //fn进去 Promise化的fn出来 实现之
    return function pfn(...args) {
      return new Promise(
        /* executor */
        (resolve, reject) => {
          /* 想要履约6 还得调用multiply */
          // const ret = fn(...args,(...a) => resolve(a))
          const ret = fn.apply(null, [...args, (...a) => resolve(a)]); //[6] 异步回调函数从这里resolve

          // 有返回值则履约之
          ret && resolve(ret); //同步函数从这里resolve
        }
      );
    };
  }

  /* 同步返回函数的Promise化 */
  //   const padd = promisify(add);
  //   padd(2, 3).then(
  //     (value) => console.log("value=", value) //5
  //   );

  /* 异步回调函数的Promise化 */
  const pmul = promisify(multiply);
  pmul(2, 3)
    .then((values) => {
      console.log("value=", values); //[6]
      return pmul(values[0], 4); //没法立刻履约24 就返回一个Promise 等待其继续向后履约24
    })
    .then((values) => {
      console.log("value=", values); //[24]
      return pmul(values[0], 5);
    })
    .then((values) => console.log(values[0])); //[120]
}
// fn2();

/* MongoDB引擎层封装 */
async function fn3() {
  /* 通用的获取collection连接 */
  function getCollection(dbName, collectionName) {
    //实现之
    // 连接数据库需要时间 并不能立刻返回err/collection
    return new Promise(
      /* excutor 在执行器内部去连接数据库*/
      (resolve, reject) => {
        var MongoClient = require("mongodb").MongoClient;
        var url = "mongodb://localhost:27017/";

        MongoClient.connect(url, function (err, conn) {
          if (err) {
            //   reject(err)
            resolve({
              err,
              collection: undefined,
              conn: undefined,
            });
            return;
          }

          var dbo = conn.db(dbName);
          const collection = dbo.collection(collectionName);
          resolve({
            err: undefined,
            collection,
            conn,
          });
        });
      }
    );
  }

  /* 通用插入数据 */
  async function doCreate(dbName, collectionName, dataObj) {
    //实现之
    // 延迟满足：稍后获得{err,collection}
    const { err, collection, conn } = await getCollection(
      dbName,
      collectionName
    );

    /* await以下的代码 全部相当于写在then的回调中 */
    if (err) {
      // 在then的回调中 return就是向后履约
      return {
        err,
        res: undefined,
      };
    }

    collection.insertOne(dataObj, function (err, res) {
      conn.close();

      // 将数据和插入的一并履约
      return {
        err,
        res,
      };
    });
  }

  // 模型层调用
  async function addUser(user) {
    // 对控制层返回的是一个Promise对象
    const ret = await doCreate(dbName, collectionName, user);
    return ret;
  }
}
// fn3();
